import { _decorator, Component, Camera, Button, Node, Sprite, Prefab, Toggle, Event, input, Input, Texture2D, SpriteFrame, instantiate, Vec2, UITransform, Vec3, EventTouch, EventMouse, EventKeyboard, KeyCode, EditBox } from 'cc';
const { ccclass, property } = _decorator;

import bezier_data from "./bezier_data";
import bezier_line from "./bezier_line";

@ccclass('BezierScene')
export default class bezier_scene extends Component {
    @property(Camera)
    private camera: Camera | null = null;
    @property(Button)
    private spreadButton: Button | null = null;
    @property(Node)
    private controlLayout: Node | null = null;
    @property(Node)
    private movable: Node | null = null;
    @property(Sprite)
    private bg: Sprite | null = null;
    @property(Prefab)
    private bezier_line_prefab: Prefab | null = null;
    @property(Button)
    private addBezierLineButton: Button | null = null;
    @property(Button)
    private delBezierLineButton: Button | null = null;
    @property(Button)
    private expBezierLineButton: Button | null = null;
    @property(Button)
    private impBezierLineButton: Button | null = null;
    @property(Button)
    private runBezierLineButton: Button | null = null;
    @property(Toggle)
    private hideGuideLineToggle: Toggle | null = null;
    @property(Toggle)
    private hidePointsToggle: Toggle | null = null;
    @property(EditBox)
    private editRunSpeed: EditBox | null = null;
    @property(Number)
    private runSpeed: number = 100;


    protected onLoad() {
        document.addEventListener('drop', this.dropHandler.bind(this));
        document.addEventListener('dragover', this.dragOverHandler.bind(this));

        bezier_data.bezier_scene = this;
        this.spreadButton.node.on('click', () => {
            this.controlLayout.active = !this.controlLayout.active;
            this.spreadButton.node.getChildByName('label').angle = this.controlLayout.active ? -90 : 0;
        });
        this.node.on(Node.EventType.MOUSE_WHEEL, this.onMouseWheel, this);
        this.node.on(Node.EventType.MOUSE_DOWN, this.onMouseDown, this);
        this.movable.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);

        input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
        input.on(Input.EventType.KEY_UP, this.onKeyUp, this);

        this.initControlPanel();
    }

    onEditRunSpeed() {
        this.runSpeed = parseFloat(this.editRunSpeed.string);
    }

    private initControlPanel() {
        this.addBezierLineButton.node.on(Button.EventType.CLICK, this.addBezierLine, this);
        this.delBezierLineButton.node.on(Button.EventType.CLICK, this.delCurBezierLine, this);
        this.expBezierLineButton.node.on(Button.EventType.CLICK, this.expBezierLine, this);
        this.impBezierLineButton.node.on(Button.EventType.CLICK, this.impBezierLine, this);
        this.runBezierLineButton.node.on(Button.EventType.CLICK, this.runBezierLine, this);
        this.hideGuideLineToggle.node.on(Toggle.EventType.TOGGLE, this.onHideGuideLine, this);
        this.hidePointsToggle.node.on(Toggle.EventType.TOGGLE, this.onHidePoints, this);
    }
    protected start() {
        this.addBezierLine();
    }
    public draw() {
        for (let bLine of bezier_data.bezierLines) {
            bLine.draw();
        }
    }
    private dropHandler(event: DragEvent) {
        event.preventDefault();
        if (event.dataTransfer.files && event.dataTransfer.files.length > 0) {
            const file = event.dataTransfer.files[0];
            // console.log(file);
            const fReader = new FileReader();
            if (file.type.includes('image')) {
                fReader.readAsDataURL(file);
                fReader.onload = event => {
                    const image = new Image();
                    image.src = (event.target.result as string);
                    const sp = SpriteFrame.createWithImage(image);
                    this.bg.spriteFrame = sp;
                };
            } else if (file.type.includes('json')) {
                fReader.readAsText(file);
                fReader.onload = event => {
                    // console.log(event.target.result);
                    const jsonData = JSON.parse(event.target.result as string);
                    this.drawBezierLineByJsonData(jsonData);
                };
            } else {
                // do nothing
            }
        }
    }
    private dragOverHandler(event: DragEvent) {
        event.preventDefault();
    }
    private addBezierLine() {
        const line = this._addBezierLine();
        line.init();
    }
    private _addBezierLine() {
        // 默认以屏幕空间的中心0,0点，添加贝塞尔曲线
        const zeroPointWorld = this.node.getComponent(UITransform).convertToWorldSpaceAR(Vec3.ZERO);
        const zeroPointMovable = this.movable.getComponent(UITransform).convertToNodeSpaceAR(zeroPointWorld);
        const bLineNode = instantiate(this.bezier_line_prefab);
        bLineNode.parent = this.bg.node;
        bLineNode.setPosition(zeroPointMovable);
        const bLine = bLineNode.getComponent(bezier_line);
        bezier_data.bezierLines.push(bLine);
        bezier_data.curBezierLineIndex = bezier_data.bezierLines.length - 1;
        return bLine;
    }
    private delBezierLine(index: number) {
        // 防止正在运行中的路径点报错
        this.unscheduleAllCallbacks();
        if (bezier_data.bezierLines[index]) {
            const line = bezier_data.bezierLines.splice(index, 1);
            line[0].node.destroy();
            // 重置当前贝塞尔曲线id
            if (bezier_data.bezierLines.length > 0) bezier_data.curBezierLineIndex = bezier_data.bezierLines.length - 1;
            else bezier_data.curBezierLineIndex = -1;
        }
        this.draw();
    }
    public delCurBezierLine() {
        this.delBezierLine(bezier_data.curBezierLineIndex);
    }
    private expBezierLine() {
        const BezierData: BezierJsonFormat[] = [];
        for (let line of bezier_data.bezierLines) {
            const LineData: BezierJsonFormat = {
                LP: [line.node.x, line.node.y],                       // Line Position
                PP: line.bezierPoints.map(v => [v.node.x, v.node.y]), // Point Position
                speed: this.runSpeed,
            };
            BezierData.push(LineData);
        }
        const BezierDataString = JSON.stringify(BezierData, null, 2);
        const anchor = document.createElement('a');
        anchor.setAttribute('href', `data:text/plain;charset=utf-8,${encodeURIComponent(BezierDataString)}`);
        anchor.setAttribute('download', 'bezier_lines_data.json');
        anchor.click();
    }
    private impBezierLine() {
        const input = document.createElement('input');
        input.setAttribute('type', 'file');
        input.setAttribute('accept', 'application/json');
        input.onchange = () => {
            if (input.files && input.files.length > 0) {
                const fReader = new FileReader();
                fReader.onload = event => {
                    const jsonData = JSON.parse(event.target.result as string);
                    this.drawBezierLineByJsonData(jsonData);
                };
                fReader.readAsText(input.files[0]);
            }
        };
        input.click();
    }

    /** 运行 */
    private runBezierLine() {
        //const line = bezier_data.bezierLines[bezier_data.curBezierLineIndex];
        for (let i = 0; i < bezier_data.bezierLines.length; i++) {
            const line_all = bezier_data.bezierLines[i];
            if (line_all) {
                this.scheduleOnce(() => line_all.run(this.runSpeed), 0);
            }
        }

    }
    private drawBezierLineByJsonData(jsonData: BezierJsonFormat[]) {
        // 根据json数据绘制贝塞尔曲线
        console.log(jsonData);
        for (let i = 0; i < jsonData.length; ++i) {
            const lineData = jsonData[i];
            if (lineData.PP.length < 4 || lineData.PP.length % 3 !== 1) {
                console.log(`imported line data ${i} error, check PP length: ${lineData.PP.length}`);
                continue;
            }
            const lineNode = instantiate(this.bezier_line_prefab);
            lineNode.parent = this.bg.node;
            lineNode.setPosition(lineData.LP[0], lineData.LP[1]);
            const bLine = lineNode.getComponent(bezier_line);
            bLine.initWithPositionArray(lineData.PP);
            bezier_data.bezierLines.push(bLine);
            bezier_data.curBezierLineIndex = bezier_data.bezierLines.length - 1;
        }
        this.draw();
    }
    private onHideGuideLine(toggle: Toggle) {
        bezier_data.drawGuideLines = !toggle.isChecked;
        this.draw();
    }
    private onHidePoints(toggle: Toggle) {
        this.hideGuideLineToggle.isChecked = true;
        bezier_data.drawGuideLines = false;
        for (let line of bezier_data.bezierLines) {
            for (let point of line.bezierPoints) {
                point.node.active = !toggle.isChecked;
            }
        }
        this.draw();
    }
    /** 移动所有线、点 */
    private onTouchMove(event: EventTouch) {
        const delta = event.getDelta();
        this.movable.x += delta.x;
        this.movable.y += delta.y;
    }
    private onMouseWheel(event: EventMouse) {
        // 根据滚轮，缩放背景板
        const scrollY = event.getScrollY();
        let scale = this.movable.scale.x;
        if (scrollY > 0) {
            scale += 0.05;
            if (scale > 10) scale = 10;
        } else {
            scale -= 0.05;
            if (scale < 0.1) scale = 0.1;
        }
        this.movable.setScale(scale, scale, 1);
    }
    private onMouseDown(event: EventMouse) {
        const mouseButton = event.getButton();
        if (mouseButton === EventMouse.BUTTON_MIDDLE) {
            this.movable.setScale(Vec3.ONE);
        }
    }
    private onKeyDown(event: EventKeyboard) {
        if (event.keyCode === KeyCode.SHIFT_LEFT) {
            bezier_data.shiftPressed = true;
        }

        if (event.keyCode === KeyCode.SPACE) {
            const line = bezier_data.bezierLines[bezier_data.curBezierLineIndex];
            line.is_addspeed = true;
        }
    }
    private onKeyUp(event: EventKeyboard) {
        if (event.keyCode === KeyCode.SHIFT_LEFT) {
            bezier_data.shiftPressed = false;
        }
        
        if (event.keyCode === KeyCode.SPACE) {
            const line = bezier_data.bezierLines[bezier_data.curBezierLineIndex];
            line.is_addspeed = false;
        }
    }
    //    // update (dt) {}
}
